{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 读二进制文件"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 用fetch_openml（）读取.mat文件"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.datasets import fetch_openml\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "mnist = fetch_openml(\"mnist_784\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "#X, y  = mnist['data'], mnist['target'].astype(np.int32)\n",
    "X, y  = mnist['data'], mnist['target']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "'5'"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import matplotlib\n",
    "%matplotlib inline\n",
    "\n",
    "some_digit = X[0]\n",
    "some_digit_image = some_digit.reshape(28, 28)\n",
    "plt.imshow(some_digit_image, cmap = matplotlib.cm.binary)\n",
    "plt.show()\n",
    "y[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 建立测试集和训练集"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "X_train, X_test, y_train, y_test = X[:60000], X[60000:], y[:60000], y[60000:]\n",
    "\n",
    "# 将数据集合交叉洗牌，交叉验证时，每个子集合数据分布均匀，有些机器学习算法对训练实例的顺序敏感\n",
    "shuffle_index = np.random.permutation(60000)  # 产生一个随机排列的0~60000索引\n",
    "X_train, y_train = X_train[shuffle_index], y_train[shuffle_index] # 分割测试集和训练集"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## KNN分类器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0.97083333, 0.97308333, 0.97191667, 0.97258333, 0.97375   ])"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#KNN 算法\n",
    "from sklearn.neighbors import KNeighborsClassifier\n",
    "from sklearn.model_selection import cross_val_score,GridSearchCV\n",
    "\n",
    "knn_clf = KNeighborsClassifier(n_neighbors = 5, weights = 'distance')\n",
    "\n",
    "cross_val_score(knn_clf, X_train, y_train, cv = 5, scoring = \"accuracy\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "KNeighborsClassifier(weights='distance')"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "knn_clf.fit(X_train, y_train)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array(['7', '2', '1', ..., '4', '5', '6'], dtype=object)"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y_pred = knn_clf.predict(X_test)\n",
    "y_pred\n",
    "#precision_score(y_test, y_pred) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 974,    1,    1,    0,    0,    1,    2,    1,    0,    0],\n",
       "       [   0, 1133,    2,    0,    0,    0,    0,    0,    0,    0],\n",
       "       [  11,    7,  989,    2,    0,    0,    2,   17,    4,    0],\n",
       "       [   0,    2,    3,  973,    1,   13,    1,    7,    4,    6],\n",
       "       [   2,    7,    0,    0,  943,    0,    4,    3,    0,   23],\n",
       "       [   4,    0,    0,    9,    2,  861,    6,    1,    4,    5],\n",
       "       [   5,    3,    0,    0,    3,    2,  945,    0,    0,    0],\n",
       "       [   0,   20,    4,    0,    3,    0,    0,  990,    0,   11],\n",
       "       [   7,    3,    5,   12,    5,   11,    5,    5,  916,    5],\n",
       "       [   3,    5,    3,    7,    7,    3,    1,   11,    2,  967]],\n",
       "      dtype=int64)"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from sklearn.metrics import confusion_matrix\n",
    "\n",
    "conf_mat = confusion_matrix(y_test, y_pred)\n",
    "conf_mat"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0.99387755, 0.99823789, 0.95833333, 0.96336634, 0.96028513,\n",
       "       0.96524664, 0.98643006, 0.96303502, 0.94045175, 0.95837463])"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "accuracy = np.diagonal(conf_mat)/conf_mat.sum(axis = 1)\n",
    "accuracy"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 精度均在90%以上，‘8’的精度最差，‘1’的精度最高"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 网格搜索KNN分类器优化参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "GridSearchCV(cv=3, estimator=KNeighborsClassifier(weights='distance'),\n",
       "             param_grid=[{'n_neighbors': [5, 7, 9],\n",
       "                          'weights': ['uniform', 'distance']}],\n",
       "             return_train_score=True, scoring='accuracy')"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 需要调优的模型参数（KNN）\n",
    "param_grid = [\n",
    "    {'n_neighbors': [5, 7, 9], 'weights': ['uniform','distance']},\n",
    "  ]\n",
    "\n",
    "grid_search = GridSearchCV(knn_clf, param_grid, cv=3, scoring='accuracy', return_train_score=True)\n",
    "grid_search.fit(X_train, y_train)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 最优模型参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'n_neighbors': 5, 'weights': 'distance'}"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "grid_search.best_params_"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.9686833333333333 {'n_neighbors': 5, 'weights': 'uniform'}\n",
      "0.97045 {'n_neighbors': 5, 'weights': 'distance'}\n",
      "0.9670166666666667 {'n_neighbors': 7, 'weights': 'uniform'}\n",
      "0.9684166666666666 {'n_neighbors': 7, 'weights': 'distance'}\n",
      "0.9659833333333333 {'n_neighbors': 9, 'weights': 'uniform'}\n",
      "0.96755 {'n_neighbors': 9, 'weights': 'distance'}\n"
     ]
    }
   ],
   "source": [
    "cvres = grid_search.cv_results_\n",
    "for mean_score, params in zip(cvres[\"mean_test_score\"], cvres[\"params\"]):\n",
    "    print(mean_score, params)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'mean_fit_time': array([20.55372818, 20.80411148, 20.73107767, 20.54205481, 20.57704918,\n",
       "        20.37471128]),\n",
       " 'std_fit_time': array([0.17666204, 0.6026283 , 0.1697951 , 0.21423399, 0.14437633,\n",
       "        0.05787713]),\n",
       " 'mean_score_time': array([816.61499985, 830.69085685, 819.50488742, 824.5354406 ,\n",
       "        810.72102404, 812.74737763]),\n",
       " 'std_score_time': array([ 3.73428638, 28.73987794,  6.90717089, 10.26744465,  8.53979023,\n",
       "         0.99350319]),\n",
       " 'param_n_neighbors': masked_array(data=[5, 5, 7, 7, 9, 9],\n",
       "              mask=[False, False, False, False, False, False],\n",
       "        fill_value='?',\n",
       "             dtype=object),\n",
       " 'param_weights': masked_array(data=['uniform', 'distance', 'uniform', 'distance',\n",
       "                    'uniform', 'distance'],\n",
       "              mask=[False, False, False, False, False, False],\n",
       "        fill_value='?',\n",
       "             dtype=object),\n",
       " 'params': [{'n_neighbors': 5, 'weights': 'uniform'},\n",
       "  {'n_neighbors': 5, 'weights': 'distance'},\n",
       "  {'n_neighbors': 7, 'weights': 'uniform'},\n",
       "  {'n_neighbors': 7, 'weights': 'distance'},\n",
       "  {'n_neighbors': 9, 'weights': 'uniform'},\n",
       "  {'n_neighbors': 9, 'weights': 'distance'}],\n",
       " 'split0_test_score': array([0.9682 , 0.9701 , 0.96765, 0.96895, 0.96685, 0.9686 ]),\n",
       " 'split1_test_score': array([0.9673 , 0.96895, 0.96555, 0.9667 , 0.96445, 0.96595]),\n",
       " 'split2_test_score': array([0.97055, 0.9723 , 0.96785, 0.9696 , 0.96665, 0.9681 ]),\n",
       " 'mean_test_score': array([0.96868333, 0.97045   , 0.96701667, 0.96841667, 0.96598333,\n",
       "        0.96755   ]),\n",
       " 'std_test_score': array([0.00137012, 0.00138984, 0.0010403 , 0.00124253, 0.0010873 ,\n",
       "        0.00114964]),\n",
       " 'rank_test_score': array([2, 1, 5, 3, 6, 4]),\n",
       " 'split0_train_score': array([0.978775, 1.      , 0.975575, 1.      , 0.972825, 1.      ]),\n",
       " 'split1_train_score': array([0.97955, 1.     , 0.97525, 1.     , 0.9731 , 1.     ]),\n",
       " 'split2_train_score': array([0.978375, 1.      , 0.97425 , 1.      , 0.97205 , 1.      ]),\n",
       " 'mean_train_score': array([0.9789    , 1.        , 0.975025  , 1.        , 0.97265833,\n",
       "        1.        ]),\n",
       " 'std_train_score': array([0.00048777, 0.        , 0.00056384, 0.        , 0.00044457,\n",
       "        0.        ])}"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "grid_search.cv_results_"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [],
   "source": [
    "best_knn = KNeighborsClassifier(n_neighbors = 5, weights = 'distance')\n",
    "y_pred = knn_clf.predict(X_test)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 精度和召回率"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0.96819085, 0.95935648, 0.98212512, 0.97008973, 0.97821577,\n",
       "       0.96632997, 0.97826087, 0.95652174, 0.98494624, 0.95083579])"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from sklearn.metrics import precision_score, recall_score\n",
    "\n",
    "#y_train_pred = knn_clf.predict([some_digit])\n",
    "precision_score(y_test, y_pred, average = None)  # 精度 "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0.99387755, 0.99823789, 0.95833333, 0.96336634, 0.96028513,\n",
       "       0.96524664, 0.98643006, 0.96303502, 0.94045175, 0.95837463])"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "recall_score(y_test, y_pred, average = None)  # 召回率"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0.98086606, 0.97841105, 0.97008337, 0.96671634, 0.96916752,\n",
       "       0.965788  , 0.98232848, 0.95976733, 0.96218487, 0.95459033])"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from sklearn.metrics import f1_score\n",
    "\n",
    "f1_score(y_test, y_pred, average = None) #F1 分数 "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 分类器对各个数字的分辨精度和召回率都达到90%以上"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 扩展训练集"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 将MNIST图片向任意方向（上，下，左，右）移动一个像素功能。然后对训练集中的每张图片，创建四个位移后的副本，每个方向一个，添加到训练集。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0 [0 1 2 3]\n",
      "1 [4 5 6 7]\n",
      "2 [ 8  9 10 11]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "array([1., 2., 3.])"
      ]
     },
     "execution_count": 54,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr = np.arange(12).reshape(3,4)\n",
    "up = np.vstack((arr[1:,:],np.zeros([1,4])))\n",
    "for i, line in enumerate(arr):\n",
    "    print(i, line)\n",
    "    \n",
    "#arr2 = np.array(['c']*4)\n",
    "arr2 = np.zeros((3,4))\n",
    "arr2[:-1,:] = arr[1:,:]\n",
    "arr3 = np.array([1,2,3,4,5])\n",
    "arr4  = np.zeros((arr2.shape[0],))\n",
    "arr4[:]=[1,2,3]\n",
    "arr4\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.base import BaseEstimator, TransformerMixin\n",
    "import pandas as pd\n",
    "\n",
    "class SampleAdder(BaseEstimator, TransformerMixin):\n",
    "    def __init__(self, nShiftPixel = 1, nImageSize = 28):\n",
    "        self.nShiftPixel = nShiftPixel\n",
    "        self.nImageSize = nImageSize\n",
    "        \n",
    "    def fit(self, X, y = None):\n",
    "        return self\n",
    "    \n",
    "    def transform(self, X, y = None):\n",
    "        nShift = self.nShiftPixel\n",
    "        nSize = self.nImageSize\n",
    "        newX = np.zeros((X.shape[0]*5, X.shape[1]))\n",
    "        newY = np.empty((y.shape[0]*5,),dtype = str)\n",
    "        \n",
    "        #newX = X.copy()\n",
    "        #newY = y.copy()\n",
    "        \n",
    "        for i, img in enumerate(X):\n",
    "            newX[5*i,:] = img\n",
    "                        \n",
    "            img1 = img.reshape(nSize,nSize)            \n",
    "            arrUp = np.vstack((img1[nShift:,:],np.zeros([nShift,nSize]))).reshape(1,-1)\n",
    "            arrDown = np.vstack((np.zeros([nShift,nSize]),img1[:-nShift,:])).reshape(1,-1)\n",
    "            arrLeft = np.hstack((img1[:,nShift:],np.zeros([nSize,nShift]))).reshape(1,-1)\n",
    "            arrRight = np.hstack((np.zeros([nSize,nShift]),img1[:,:-nShift],)).reshape(1,-1)\n",
    "            \n",
    "            newX[5*i+1,:] = arrUp[0,:]\n",
    "            newX[5*i+2,:] = arrDown[0,:]\n",
    "            newX[5*i+3,:] = arrLeft[0,:]\n",
    "            newX[5*i+4,:] = arrRight[0,:]\n",
    "            newY[5*i:5*i+5] = [y[i]]*5\n",
    "         \n",
    "        shuffle_index = np.random.permutation(newX.shape[0])  # 产生一个随机排列索引\n",
    "        return newX[shuffle_index], newY[shuffle_index] \n",
    "\n",
    "sample_adder = SampleAdder(1,28)\n",
    "newX, newY = sample_adder.transform(X_train[:1000], y_train[:1000])  # 数据量太大，只用前1000张图"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "原训练集精度：  [0.905 0.895 0.875 0.87  0.87 ]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "array([0.9441675 , 0.89532117, 0.88935722, 0.87893701, 0.85359265,\n",
       "       0.87135506, 0.93843766, 0.88226673, 0.8573015 , 0.83942619])"
      ]
     },
     "execution_count": 58,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "knn_clf = KNeighborsClassifier(n_neighbors = 5, weights = 'distance')\n",
    "\n",
    "print('原训练集精度： ', cross_val_score(knn_clf, X_train[:1000], y_train[:1000], cv = 5, scoring = \"accuracy\"))\n",
    "knn_clf.fit(X_train[:1000], y_train[:1000])\n",
    "y_pred2 = knn_clf.predict(X_test)\n",
    "f1_score(y_test, y_pred2, average = None)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "扩展训练集精度：  [0.962 0.948 0.958 0.954 0.965]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "array([0.95604396, 0.91357027, 0.91933816, 0.89530333, 0.88948211,\n",
       "       0.89064262, 0.94720497, 0.90310078, 0.8761799 , 0.88380952])"
      ]
     },
     "execution_count": 61,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\n",
    "print('扩展训练集精度： ', cross_val_score(knn_clf, newX, newY, cv = 5, scoring = \"accuracy\"))\n",
    "knn_clf.fit(newX, newY)\n",
    "y_pred3 = knn_clf.predict(X_test)\n",
    "f1_score(y_test, y_pred3, average = None)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 利用扩展训练集训练模型，F1分数提高2-5%"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
